﻿
// HoardTokenDlg.cpp: 实现文件
//

#include "pch.h"
#include "framework.h"
#include "HoardToken.h"
#include "HoardTokenDlg.h"
#include "afxdialogex.h"
#include <vector>

#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// CHoardTokenDlg 对话框



CHoardTokenDlg::CHoardTokenDlg(CWnd* pParent /*=nullptr*/)
	: CDialogEx(IDD_HOARDTOKEN_DIALOG, pParent)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CHoardTokenDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_LIST_PLAN, m_lstPlan);
	DDX_Control(pDX, IDC_EDIT_TOTAL_FUNDS, m_edtTotalFunds);
	DDX_Control(pDX, IDC_EDIT_PRICE_MAX, m_edtPriceMax);
	DDX_Control(pDX, IDC_EDIT_PRICE_MIN, m_edtPriceMin);
	DDX_Control(pDX, IDC_EDIT_TRADE_RATE, m_edtTradeRate);
	DDX_Control(pDX, IDC_EDIT_GRAIN_SIZE, m_edtGrainSize);
	DDX_Control(pDX, IDC_EDIT_RECOVER_FUNDS, m_edtRecoverFunds);
	DDX_Control(pDX, IDC_EDIT_PRICE_SCALE, m_edtPriceScale);
	DDX_Control(pDX, IDC_EDIT_AMOUNT_SCALE, m_edtAmountScale);
}

BEGIN_MESSAGE_MAP(CHoardTokenDlg, CDialogEx)
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_WM_CLOSE()
	ON_WM_DESTROY()
	ON_BN_CLICKED(IDC_BUTTON_CALC, &CHoardTokenDlg::OnClickedButtonCalc)
END_MESSAGE_MAP()


// CHoardTokenDlg 消息处理程序

BOOL CHoardTokenDlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();

	// 设置此对话框的图标。  当应用程序主窗口不是对话框时，框架将自动
	//  执行此操作
	SetIcon(m_hIcon, TRUE);			// 设置大图标
	SetIcon(m_hIcon, FALSE);		// 设置小图标

	RECT rc;
	int iCount = 0;
	int iWidth = 0;
	DWORD dwStyle = 0;

	dwStyle = m_lstPlan.GetExtendedStyle();
	dwStyle |= LVS_EX_FULLROWSELECT;
	m_lstPlan.SetExtendedStyle(dwStyle);

	m_lstPlan.GetWindowRect(&rc);
	iWidth = (rc.right - rc.left -25) / 13;
	m_lstPlan.InsertColumn(iCount++, _TEXT("ID"), LVCFMT_CENTER, iWidth);
	m_lstPlan.InsertColumn(iCount++, _TEXT("买入价格"), LVCFMT_CENTER, iWidth * 2);
	m_lstPlan.InsertColumn(iCount++, _TEXT("买入数量"), LVCFMT_CENTER, iWidth * 2);
	m_lstPlan.InsertColumn(iCount++, _TEXT("本次资金"), LVCFMT_CENTER, iWidth * 2);
	m_lstPlan.InsertColumn(iCount++, _TEXT("买入总量"), LVCFMT_CENTER, iWidth * 2);
	m_lstPlan.InsertColumn(iCount++, _TEXT("总资金"), LVCFMT_CENTER, iWidth * 2);
	m_lstPlan.InsertColumn(iCount++, _TEXT("回本价格"), LVCFMT_CENTER, iWidth * 2);

	m_edtTotalFunds.SetWindowText(_T("200000"));
	m_edtPriceMax.SetWindowText(_T("6000"));
	m_edtPriceMin.SetWindowText(_T("3000"));
	m_edtTradeRate.SetWindowText(_T("0.00075"));
	m_edtGrainSize.SetWindowText(_T("0.012"));
	m_edtRecoverFunds.SetWindowText(_T("800"));
	m_edtPriceScale.SetWindowText(_T("2"));
	m_edtAmountScale.SetWindowText(_T("6"));

	return TRUE;  // 除非将焦点设置到控件，否则返回 TRUE
}

// 如果向对话框添加最小化按钮，则需要下面的代码
//  来绘制该图标。  对于使用文档/视图模型的 MFC 应用程序，
//  这将由框架自动完成。

void CHoardTokenDlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this); // 用于绘制的设备上下文

		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

		// 使图标在工作区矩形中居中
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// 绘制图标
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialogEx::OnPaint();
	}
}

//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CHoardTokenDlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}

void CHoardTokenDlg::OnClose()
{
	EndDialog(IDCANCEL);
	CDialogEx::OnClose();
}

void CHoardTokenDlg::OnDestroy()
{
	CDialogEx::OnDestroy();

	// TODO: 在此处添加消息处理程序代码
}

typedef struct
{
	int id;
	double dBuyPrice;
	double dBuyAmount;
	double dBuyFunds;
	double dBuyTotalAmount;
	double dBuyTotalFunds;
	double dRecoverPrice;
} PlanItem;

void CHoardTokenDlg::OnClickedButtonCalc()
{
	CString strTotalFunds;
	CString strPriceMax;
	CString strPriceMin;
	CString strTradeRate;
	CString strGrainSize;
	CString strRecoverFunds;
	CString strPriceScale;
	CString strAmountScale;

	double dTotalFunds;
	double dPriceMax;
	double dPriceMin;
	double dTradeRate;
	double dGrainSize;
	double dRecoverFunds;
	int iPriceScale;
	int iAmountScale;

	TCHAR* pEnd = nullptr;

	m_edtTotalFunds.GetWindowText(strTotalFunds);
	m_edtPriceMax.GetWindowText(strPriceMax);
	m_edtPriceMin.GetWindowText(strPriceMin);
	m_edtTradeRate.GetWindowText(strTradeRate);
	m_edtGrainSize.GetWindowText(strGrainSize);
	m_edtRecoverFunds.GetWindowText(strRecoverFunds);
	m_edtPriceScale.GetWindowText(strPriceScale);
	m_edtAmountScale.GetWindowText(strAmountScale);

	if (strTotalFunds.IsEmpty() || strPriceMax.IsEmpty() || strPriceMin.IsEmpty()
		|| strTradeRate.IsEmpty() || strGrainSize.IsEmpty() || strRecoverFunds.IsEmpty()
		|| strPriceScale.IsEmpty() || strAmountScale.IsEmpty())
	{
		MessageBox(_TEXT("参数不全"), _TEXT("错误"), MB_OK | MB_ICONERROR);
		return;
	}

	dTotalFunds = _tcstod(strTotalFunds, &pEnd);
	dPriceMax = _tcstod(strPriceMax, &pEnd);
	dPriceMin = _tcstod(strPriceMin, &pEnd);
	dTradeRate = _tcstod(strTradeRate, &pEnd);
	dGrainSize = _tcstod(strGrainSize, &pEnd);
	dRecoverFunds = _tcstod(strRecoverFunds, &pEnd);
	iPriceScale = _ttoi(strPriceScale);
	iAmountScale = _ttoi(strAmountScale);

	m_lstPlan.DeleteAllItems();

	CString strTmp;
	int iCount = 0;
	double dCurPrice = dPriceMax;
	double dTmp = dPriceMin * (1 - dGrainSize);
	std::vector<PlanItem> vecPlan;
	PlanItem piInfo;

	// 计算买入价格
	while (dCurPrice > dTmp)
	{
		memset(&piInfo, 0, sizeof(piInfo));

		piInfo.id = iCount + 1;

		strTmp.Format(_T("%.*lf"), iPriceScale, dCurPrice);
		piInfo.dBuyPrice = _tcstod(strTmp, &pEnd);

		dPriceMin = piInfo.dBuyPrice;
		vecPlan.push_back(piInfo);
		dCurPrice *= (1 - dGrainSize);
		iCount++;
	}

	iCount = 0;
	double dRecoverRate = dRecoverFunds / (dPriceMax - dPriceMin);

	// 计算回本价格
	for (auto iter = vecPlan.begin(); iter != vecPlan.end(); iter++)
	{
		PlanItem& pi = *iter;

		if (0 == iCount)
		{
			dTmp = dPriceMax * (1 + dTradeRate) / (1 - dTradeRate);
			strTmp.Format(_T("%.*lf"), iPriceScale, dTmp);
			pi.dRecoverPrice = _tcstod(strTmp, &pEnd);
		}
		else
		{
			dTmp = (dPriceMax - pi.dBuyPrice) * dRecoverRate + pi.dBuyPrice;
			strTmp.Format(_T("%.*lf"), iPriceScale, dTmp);
			pi.dRecoverPrice = _tcstod(strTmp, &pEnd);
		}

		iCount++;
	}

	double dCurFunds = dTotalFunds;

	// 计算买入数量
	for (auto iter = vecPlan.rbegin(); iter != vecPlan.rend(); iter++)
	{
		PlanItem& pi = *iter;
		auto itNext = iter + 1;

		if (itNext != vecPlan.rend())
		{
			dTmp = dCurFunds / (pi.dRecoverPrice * (1 - dTradeRate));
			strTmp.Format(_T("%.*lf"), iAmountScale, dTmp);
			pi.dBuyTotalAmount = _tcstod(strTmp, &pEnd);

			dTmp = (pi.dBuyTotalAmount * (itNext->dRecoverPrice - pi.dRecoverPrice)) 
				/ (itNext->dRecoverPrice - (pi.dBuyPrice * ((1 + dTradeRate) / (1 - dTradeRate))));
			strTmp.Format(_T("%.*lf"), iAmountScale, dTmp);
			pi.dBuyAmount = _tcstod(strTmp, &pEnd);

			dCurFunds -= pi.dBuyPrice * pi.dBuyAmount * (1 + dTradeRate);
		}
		else
		{
			auto itPrev = iter - 1;

			dTmp = itPrev->dBuyTotalAmount - itPrev->dBuyAmount;
			strTmp.Format(_T("%.*lf"), iAmountScale, dTmp);
			pi.dBuyAmount = pi.dBuyTotalAmount = _tcstod(strTmp, &pEnd);
		}

		dTmp = pi.dBuyPrice * pi.dBuyAmount * (1 + dTradeRate);
		strTmp.Format(_T("%.*lf"), iPriceScale, dTmp);
		pi.dBuyFunds = _tcstod(strTmp, &pEnd);
	}

	dTmp = 0;

	// 计算买入总资金
	for (auto iter = vecPlan.begin(); iter != vecPlan.end(); iter++)
	{
		PlanItem& pi = *iter;

		dTmp += pi.dBuyFunds;
		strTmp.Format(_T("%.*lf"), iPriceScale, dTmp);
		pi.dBuyTotalFunds = _tcstod(strTmp, &pEnd);
	}

	int iSubItem;
	iCount = 0;

	for (auto iter = vecPlan.begin(); iter != vecPlan.end(); iter++)
	{
		iSubItem = 1;
		PlanItem& pi = *iter;

		strTmp.Format(_T("%02d"), pi.id);
		m_lstPlan.InsertItem(iCount, strTmp);

		strTmp.Format(_T("%.*lf"), iPriceScale, pi.dBuyPrice);
		m_lstPlan.SetItemText(iCount, iSubItem++, strTmp);

		strTmp.Format(_T("%.*lf"), iAmountScale, pi.dBuyAmount);
		m_lstPlan.SetItemText(iCount, iSubItem++, strTmp);

		strTmp.Format(_T("%.*lf"), iPriceScale, pi.dBuyFunds);
		m_lstPlan.SetItemText(iCount, iSubItem++, strTmp);

		strTmp.Format(_T("%.*lf"), iAmountScale, pi.dBuyTotalAmount);
		m_lstPlan.SetItemText(iCount, iSubItem++, strTmp);

		strTmp.Format(_T("%.*lf"), iPriceScale, pi.dBuyTotalFunds);
		m_lstPlan.SetItemText(iCount, iSubItem++, strTmp);

		strTmp.Format(_T("%.*lf"), iPriceScale, pi.dRecoverPrice);
		m_lstPlan.SetItemText(iCount, iSubItem++, strTmp);

		iCount++;
	}
}
